from lxml import etree,html
from sets import Set
from APIExceptions import *
class DataNode(object):
    """
    This container contains the response data from webserver. Stored as lxml.etree element
    """
    def __init__(self,node,namespace=None,parse_as="xml"):
        """
        Initialize with a DataContainer node or xml/html text.
        """
        myclass=node.__class__ 
        if myclass == self.__class__:
            #this is a Data container.
            self.data=node.data
            self.namespace=node.namespace
            self.__mytype__=node.__mytype__
        elif myclass == etree._Element:
            #is a lxml object
            self.data=node
            if self.data.nsmap:
                self.namespace="{%s}" % self.data.nsmap[None]
            else:
                self.namespace=""
        elif myclass == str :
            #is string
            #if contains no < or [ or {
            if not '<' in node and not '[' in node and not '{' in node:
                #node is not a xml/html/json string, possiblely tag name 
                if namespace:
                    self.data=etree.Element("{%s}%s"% (namespace,node),nsmap={None : namespace})
                    self.namespace="{%s}" % namespace
                else:
                    self.namespace=""
                    self.data=etree.Element(node)
                self.__mytype__=parse_as
                return
            if parse_as is 'xml':
                self.data=etree.fromstring(node)
                if self.data.nsmap:
                    self.namespace="{%s}" % self.data.nsmap[None]
                else:
                    self.namespace=""
                self.__mytype__='xml'
            elif parse_as is 'html':
                self.data=html.fromstring(node)
                self.__mytype__='html'
            elif parse_as is 'json':
                pass
    def setNamespace(self,namespace):
        if namespace:
            self.namespace="{%s}" % namespace
        else:
            self.namespace=""
    def getNamespace(self):
         return self.namespace
    def getChildByName(self,tag):
        for child in self.data.iterchildren(self.namespace+tag):
            return (DataNode(child,self.namespace))
        errmsg=" ".join(self.getChildrenName())
        raise Exception("No such key exists for current Node! Suitable key should be:\n%s" % (errmsg))
    def getDescedentByName(self,tag):
        found=[]
        for child in self.data.iter(self.namespace+tag):
            found.append(DataNode(child,self.namespace))
        return found
    def append(self,tag,value=""):
        if tag.__class__ is DataNode:
            self.data.append(tag.data)
            return DataNode
        elif tag.__class__  is str:
            #tag name 
            if self.namespace:
                newElement=etree.SubElement(self.data,self.namespace+tag)
            else:
                newElement=etree.SubElement(self.data,tag)
            newElement.text=value
            return DataNode(newElement)
        else:
            raise Exception("Wrong parameter style!")
    def hasChild(self,key):
        for child in self.data.iterchildren():
            if key == self.removeNamespaceFromTag(child.tag):
                return True
        return False
    def getChildrenName(self):
        children=Set()
        for child in self.data.iterchildren():
            children.add(self.removeNamespaceFromTag(child.tag))
        return children
    ## Return all the descendent keys(tagnames).
    def keys(self):
        return self.getDescedentsName()
    def getDescedentsName(self):
        children=Set()
        for child in self.data.iter():
            children.add(self.removeNamespaceFromTag(child.tag))
        return children
    def removeNamespaceFromTag(self,string):
        string=string.split('}')
        return string[-1]
    def setAttr(self,attr,value):
        self.data.set(attr,value)
    def getAttr(self,attr):
        #return getattr(self.data,attr)
        return self.data.get(attr)
    def set(self,value):
        self.data.text=value
    def value(self):
        if self.data.text:
            return self.data.text
        else :
            return ""
    def str(self):
        if self.data.text:
        #TODO how to avoid empty text == "   "
            return self.data.text
        else :
            return etree.tostring(self.data)
    def __str__(self):
        if self.data.text:
        #TODO how to avoid empty text == "   "
            return self.data.text
        else :
            return "<%s.%s>" % (self.__class__.__name__,self.removeNamespaceFromTag(self.data.tag))
    def __repr__(self):
        if self.data.text:
            return self.data.text
        else :
            return "<%s.%s>" % (self.__class__.__name__,self.removeNamespaceFromTag(self.data.tag))
    def __eq__(self,string):
        if type(string) is str:
            return (self.data.text == string)
        elif type(string) is DataNode:
            return (self.data == string.data)
        else:
            raise Exception("Type %s incompatible!" % type(string))
    def __iter__(self):
        raise Exception("This object is not iteratable.")
    def __getattr__(self,tag):
        return self.getChildByName(tag)
    def __getitem__(self,tag):
        if type(tag) != str:
            raise Exception("Subscription must be string.")
        if self.__mytype__ is 'xml':
           return self.getDescedentByName(tag)
        else:
            return self.data.cssselect(tag)
    def __xml__(self,encoding=None,xml_declaration=None, pretty_print=False, with_tail=True, standalone=None, doctype=None, exclusive=False, with_comments=True):
        """Create a xml text"""
        return etree.tostring(self.data,method='xml',encoding=encoding,xml_declaration=xml_declaration, pretty_print=pretty_print, with_tail=with_tail, standalone=standalone, doctype=doctype, exclusive=exclusive, with_comments=with_comments)
